package top.syfy.bili.fbm.util;

import top.syfy.bili.fbm.entry.BiliCacheVideo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

/**
 * 对 entry.json 文件的属性及属性值的读写
 *
 * @author awg
 * @date 2020/10/18 星期日
 */
public class JSONAttributeUtil {

    /**
     * 缓存视频实例对象列表
     */
    public static List<BiliCacheVideo> biliCacheVideoList = new ArrayList<>();

    /**
     * 从缓存视频专辑的存储目录中解析其中子目录(单个视频的存储目录)中包含的视频信息
     *
     * @param cacheDir 缓存视频专辑的存放目录
     * @return 缓存视频实例对象列表
     * @throws IOException IO异常
     */
    public static List<BiliCacheVideo> parseCacheDir(File cacheDir) throws IOException {
        if (Objects.isNull(cacheDir) || !cacheDir.exists() || cacheDir.isFile()) {
            throw new IllegalArgumentException("该文件对象不存在或者不是一个目录");
        }
        File[] subFiles = cacheDir.listFiles();
        //若缓存视频专辑的存放目录是一个空目录，则直接返回原有的视频缓存列表
        if (Objects.isNull(subFiles)) {
            return biliCacheVideoList;
        }
        /*
            1.遍历【缓存视频专辑的存储目录】，得到其下面的文件对象（包含文件和目录(【单个缓存视频存储目录】)）
            2.对得到的文件对象进行判断，若是目录则表示该目录是【单个缓存视频存储目录】，否则就是其他文件对象(进行忽略)
            3.对【单个缓存视频存储目录】进行遍历，若是目录则表示该目录是存储音视频文件(audio.m4s、video.m4s)的目录，否则就是表示单个缓存视频的基本信息的文件(entry.json)
            4.针对相关文件或目录进行对应的操作
         */
        for (File f0 : subFiles) {
            if (f0.isDirectory()) {
                for (File f : Objects.requireNonNull(f0.listFiles())) {
                    if (f.isDirectory()) {
                        parseCacheDir(f);
                    }
                    if (DescPropertiesUtil.getProperty("ENTRY_FILE").equals(f.getName())) {
                        //获取并设置缓存视频的基本信息
                        //基本信息：【专辑名】、【BV号】、【集数】、【集数名称】
                        BiliCacheVideo v = setBiliCacheVideoTextInfo(f);
                        //基本信息：【音频部分】、【视频部分】
                        for (File subDir : Objects.requireNonNull(f.getParentFile().listFiles())) {
                            if (subDir.isDirectory()) {
                                for (File childFile : Objects.requireNonNull(subDir.listFiles())) {
                                    if (DescPropertiesUtil.getProperty("AUDIO_PART_FILE").equals(childFile.getName()) || DescPropertiesUtil.getProperty("VIDEO_PART_FILE").equals(childFile.getName())) {
                                        if (DescPropertiesUtil.getProperty("AUDIO_PART_FILE").equals(childFile.getName())) {
                                            v.setAudioPart(childFile.getAbsolutePath());
                                        }
                                        if (DescPropertiesUtil.getProperty("VIDEO_PART_FILE").equals(childFile.getName())) {
                                            v.setVideoPart(childFile.getAbsolutePath());
                                        }
                                        addVideoToVideoList(v);
                                        //break;
                                    }
                                }
                            }
                        }
                    }
                    //break;
                }
            }
        }
        //将解析出来的文件添加到缓存视频列表中
        return biliCacheVideoList;
    }

    /**
     * 将解析出来的文件添加到缓存视频列表中(判断是否有重复项，若有重复项，则不进行添加)
     * <br/>针对选集和分集需进行不同的区分: 选集判重,分集不判重
     *
     * @param newVideo 解析出来的文件
     */
    private static void addVideoToVideoList(BiliCacheVideo newVideo) throws IOException {
        // 1.若是[分集]则不判重
        if (DescPropertiesUtil.getProperty("OWNER_ID_EXISTS").equals("yes")){
            biliCacheVideoList.add(newVideo);
            return;
        }
        // 2.若是[选集]则判重
        //若缓存视频实例对象列表不为空，则进行重复项判断
        if (Objects.nonNull(biliCacheVideoList)) {
            for (BiliCacheVideo v : biliCacheVideoList) {
                //判断是否有重复项，若有重复项，则不进行添加
                if (Objects.nonNull(v) && v.getBvId().equals(newVideo.getBvId())) {
                    return;
                }
            }
        }
        //若缓存视频列表为空或者缓存视频列表中不存在要添加的缓存视频文件，则添加到其中
        biliCacheVideoList.add(newVideo);
    }

    /**
     * 将指定文件读取到内存中并将其转为HashMap，再从HashMap中获取对应的值，再把获取到的值赋值给对应的视频实体对象
     *
     * @param file 每个缓存视频的基本配置文件，一般为entry.json
     */
    private static BiliCacheVideo setBiliCacheVideoTextInfo(File file) {
        BiliCacheVideo video = new BiliCacheVideo();
        BufferedReader bufferedReader;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                sb.append(line);
            }
            String jsonStr = sb.toString();
            HashMap<?, ?> videoMap = JSON.parseObject(jsonStr, HashMap.class);
            //专辑名
            video.setTitle(getDataByKey(videoMap, DescPropertiesUtil.getProperty("ENTRY_FILE_ALBUM_NAME")));
            //BV号,https://www.bilibili.com/video/BV号
            video.setBvId(getDataByKey(videoMap, DescPropertiesUtil.getProperty("ENTRY_FILE_BVID")));
            //集数
            video.setIndex(getDataByKey(videoMap, DescPropertiesUtil.getProperty("ENTRY_FILE_INDEX")));
            //集数名称
            video.setIndexTitle(getDataByKey(videoMap, DescPropertiesUtil.getProperty("ENTRY_FILE_INDEX_TITLE")));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return video;
    }

    /**
     * 根据给定的键从给定的HashMap中获取对应的值
     *
     * @param videoMap 给定的HashMap中
     * @param key      给定的键
     * @return 给定的键与给定的HashMap对应的值
     */
    private static String getDataByKey(HashMap<?, ?> videoMap, String key) {
        if (Objects.isNull(videoMap) || Objects.isNull(key)) {
            throw new IllegalArgumentException("参数异常：缺少必要的参数");
        }
        //在配置文件中以.进行分隔多级菜单
        String[] multipleKeyArray = key.split("\\.");
        int keyLength = multipleKeyArray.length;
        //分割之后只有一个键（即使为空字符串(返回null)），则直接根据键获取值
        if (keyLength == 1) {
            return String.valueOf(videoMap.get(key));
        }
        //分割之后有多个键，则根据键递归获取值
        JSONObject tmpData = (JSONObject) videoMap.get(multipleKeyArray[0]);
        for (int i = 1; i < keyLength - 1; i++) {
            tmpData = (JSONObject) tmpData.get(multipleKeyArray[i]);
        }
        return String.valueOf(tmpData.get(multipleKeyArray[keyLength - 1]));
    }

}